/*

PROJECT 4 

PROGRAMMERS: Martin Bakiev and David Visco

*/



#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef __linux__
#include <linux/limits.h>
#else
#include <limits.h>
#endif
#include <unistd.h>
#include <sys/wait.h>
#include "utility.h"

#if !defined(PATH_MAX)
#define PATH_MAX 1024	//Use linux size for PATH_MAX if its undefined
#endif



int main()
{
	char* command = NULL;
	char* cd = malloc(PATH_MAX+1);
	getcwd(cd, PATH_MAX+1);

	for(;;)
	{
		printf("mdshell> ");
		command = getinputstring();
		sanatize(command);
		if(strcmp(command, "exit") == 0)
			break;
		if(strlen(command) == 0)
			continue;

		char **cmds = getTokens(command, "|");
		int nCmds = 0;
		for(; cmds[nCmds] != NULL; nCmds++);

		char ***pipeline = malloc(sizeof(char*) * (nCmds +1));

		for(int i = 0; cmds[i] != NULL; i++)
		{
			sanatize(cmds[i]);
			pipeline[i] = parseArgs(cmds[i]);
			free(cmds[i]);
		}
		free(cmds);
		pipeline[nCmds] = NULL;


		if(strcmp(pipeline[0][0], "cd") == 0 && nCmds == 1)
		{
			char* dir = pipeline[0][1];
			if(dir == NULL)
				dir = getenv("HOME");
			if(chdir(dir) != 0)
			printf("'%s' is not a valid directory.\n", dir);
		}
		else
		{

			pid_t pid = fork();
			if(pid == 0)
			{
				int counter = nCmds-1;
				int parent_pipe[2] = {-1,-1};

				for(;;)
				{
					pid_t pid = -1;
					int child_pipe[2] = {-1, -1};

					if(counter != 0 )
					{
						pipe(child_pipe);
						pid = fork();
					}

					if(pid == 0)
					{
						counter--;
						parent_pipe[0] = child_pipe[0];
						parent_pipe[1] = child_pipe[1];
					}
					else
					{
						waitpid(-1, NULL, 0);
						if(child_pipe[1] != -1) close(child_pipe[1]);
						if(parent_pipe[0] != -1) close(parent_pipe[0]);
						if(pipeline[counter+1] != NULL)
						{
							if(dup2(parent_pipe[1], STDOUT_FILENO) == -1)
								perror("dup2");
							if(dup2(parent_pipe[1], STDERR_FILENO) == -1)
								perror("dup2");
							if(parent_pipe[1] != STDERR_FILENO || parent_pipe[1] != STDOUT_FILENO) close(parent_pipe[1]);
						}
						if(counter != 0)
						{
							if(dup2(child_pipe[0], STDIN_FILENO) == -1)
								perror("dup2");

							if(child_pipe[0] != STDIN_FILENO) close(child_pipe[0]);
						}

						if(pipeline[counter][0] == NULL)
							return 0;

						if(strcmp(pipeline[counter][0], "pwd") == 0)
						{
							getcwd(cd, PATH_MAX);
							printf("%s\n", cd);
							return 0;
						}
						else if(strcmp(pipeline[counter][0], "echo") == 0)
						{
							for(int i = 1; pipeline[counter][i] != NULL; i++)
							{
								printf("%s", pipeline[counter][i]);
								if(pipeline[counter][i+1] != NULL)
									printf(" ");
							}
							printf("\n");
							return 0;
						}
						else
						{
							char **pipeArguments = malloc(sizeof(char*) * BUFF_SIZE);
							int argCap = BUFF_SIZE;
							int argSize = 1;
							pipeArguments[0] = pipeline[counter][0];

							for(int i = 1; pipeline[counter][i] != NULL; i++)
							{
								char **fNames = expandFileName(cd, pipeline[counter][i]);

								if(fNames[0] == NULL)
								{
									if(argSize >= BUFF_SIZE-1)
									{
										argCap *= 2;
										pipeArguments = realloc(pipeArguments, argCap);
									}
									pipeArguments[argSize] = pipeline[counter][i];
									argSize++;
									continue;
								}

								for(int j = 0; fNames[j] != NULL; j++)
								{
									if(argSize >= BUFF_SIZE-1)
									{
										argCap *= 2;
										pipeArguments = realloc(pipeArguments, argCap);
									}
									pipeArguments[argSize] = fNames[j];
									argSize++;
								}
							}
							pipeArguments[argSize] = NULL;

							if(execvp(pipeline[counter][0], pipeArguments) == -1)
							{
								perror("Failed execvp");
								return 0;
							}
						}
					}
				}
			}
			waitpid(-1, NULL, 0);
		}

		for(int i = 0; pipeline[i] != NULL; i++)
		{
			freeArr(pipeline[i]);
		}
		free(pipeline);

		free(command);
	}
	free(cd);
	free(command);
	return 0;
}
